package com.timguan.render.dataprocessor.filter;

import com.timguan.render.dataapi.domain.CmsDataDO;
import com.timguan.render.dataapi.api.ICmsDataManager;
import com.timguan.render.dataprocessor.processor.DataProcessor;
import com.timguan.render.spi.StockService;
import com.timguan.render.spi.entity.StockInfo;
import com.timguan.render.spi.mock.StockServiceMockImpl;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

/**
 *
 */
public class SoldoutProductFilter implements DataFilter {
    private static final int ADVANCE = 10;
    private static final Logger logger = LoggerFactory.getLogger(SoldoutProductFilter.class);
    private StockService stockService = new StockServiceMockImpl();
    @Autowired
    private ICmsDataManager cmsDataManagerImpl;

    public SoldoutProductFilter() {

    }

    public SoldoutProductFilter(StockService stockService) {
        this.stockService = stockService;
    }

    /**
     * 解析itemId
     *
     * @param cmsDataDOs
     * @return
     */
    private List<String> parseItemIds(List<? extends CmsDataDO> cmsDataDOs, int maxCount) {
        if (cmsDataDOs == null) {
            return null;
        }
        Set<String> itemIds = new HashSet<String>();
        int count = 0;
        for (CmsDataDO cmsDataDO : cmsDataDOs) {
            if (count < maxCount) {
                if (cmsDataDO.getItemId() != null) {
                    itemIds.add(cmsDataDO.getItemId());
                }
            }
            count++;
        }
        return new ArrayList<String>(itemIds);
    }

    /**
     * 批量获取获取商品价格
     *
     * @param itemIds
     * @return
     */
    public List<StockInfo> getStocks(List<String> itemIds) {
        if (itemIds == null || itemIds.size() == 0) {
            return null;
        }
        List<StockInfo> stockInfos = null;
        try {
            stockInfos = stockService.getStocks(itemIds);
        } catch (Exception ex) {
            logger.error("获取库存失败,itemIds:{}", Arrays.toString(itemIds.toArray(new String[itemIds.size()])));
        }
        return stockInfos;
    }


    /**
     * 查找ITEM
     *
     * @param stockInfos
     * @param itemId
     * @return
     */
    private boolean isSoldOut(List<StockInfo> stockInfos, String itemId) {
        if (stockInfos == null) {
            return false;
        }
        for (StockInfo stockInfo : stockInfos) {
            if (stockInfo != null && itemId.equals(stockInfo.getItemId())) {
                return stockInfo.isSoldout() | stockInfo.getStock() == 0;
            }
        }
        //未查询的乐观认为未售罄，等待下一次进行判断
        return false;
    }

    @Override
    public List<CmsDataDO> doFilter(List<CmsDataDO> cmsDataDOList, Map<String, String> params) {
        List<CmsDataDO> result = null;
        if (cmsDataDOList == null || cmsDataDOList.size() == 0) {
            return null;
        }
        int size = params != null && StringUtils.isNotBlank(params.get(DataProcessor.MAX_COUNT_PARAM)) &&
                StringUtils.isNumeric(params.get(DataProcessor.MAX_COUNT_PARAM)) ? Integer.parseInt(params.get(DataProcessor.MAX_COUNT_PARAM)) : 0;
        int minWeight = cmsDataManagerImpl.minWeight(cmsDataDOList.get(0).getListId());
        if (size <= 0 || cmsDataDOList.size() <= size) {
            //不存在候补商品/不需要售罄替换 不进行轮换替补
            result = cmsDataDOList;
        } else {
            List<String> itemIds = parseItemIds(cmsDataDOList, size + ADVANCE);
            //仅商品列表需要轮替
            if (itemIds != null && itemIds.size() != 0) {
                result = new ArrayList<CmsDataDO>();
                try {
                    List<StockInfo> stocks = getStocks(itemIds);
                    int abandonCount = 0;
                    int maxAbandonCount = cmsDataDOList.size() - size;//必定>0
                    int curMinWeight = minWeight - 1;
                    for (int index = 0; index < cmsDataDOList.size(); index++) {
                        if (result.size() < size) {
                            CmsDataDO cmsDataDO = cmsDataDOList.get(index);
                            if (StringUtils.isNotBlank(cmsDataDO.getItemId())) {
                                if (abandonCount < maxAbandonCount) {
                                    boolean soldOut = isSoldOut(stocks, cmsDataDO.getItemId());
                                    if (!soldOut) {
                                        result.add(cmsDataDO);
                                    } else {
                                        //1.滤除商品数
                                        abandonCount++;
                                        //2.将商品挪到列表末尾
                                        updateWeight(cmsDataDO, curMinWeight);
                                        //3.需要固定位置的元素，与后面的元素进行位置调换
                                        swapImgOrLinkWithNextData(index, cmsDataDOList);
                                        //4.minWeight--
                                        curMinWeight--;
                                    }
                                } else {
                                    result.add(cmsDataDO);
                                }
                            } else {
                                //非商品
                                result.add(cmsDataDO);
                            }
                        } else {
                            break;
                        }
                    }
                } catch (Throwable throwable) {
                    logger.error("getItemPrices failed", throwable);
                    result = cmsDataDOList.subList(0, size);
                }
            } else {
                //不包含商品，列表不需要过滤
                result = cmsDataDOList;
            }
        }
        return result;
    }

    /**
     * 当列表中图片或者链接前的元素被移除，为了保证图片或链接位置不变需要与列表中后一个数据进行位置交换
     *
     * @param startPos      被移除的元素位置
     * @param cmsDataDOList 数据列表
     */
    private void swapImgOrLinkWithNextData(int startPos, List<CmsDataDO> cmsDataDOList) {
        for (int index = startPos; index < cmsDataDOList.size() - 1; index++) {
            CmsDataDO cmsDataDO = cmsDataDOList.get(index);
            if (cmsDataDO != null && StringUtils.isBlank(cmsDataDO.getItemId())) {
                CmsDataDO nextCmsDataDO = cmsDataDOList.get(index + 1);
                cmsDataDOList.set(index, nextCmsDataDO);
                int tmpWeight = cmsDataDO.getWeight();
                updateWeight(cmsDataDO, nextCmsDataDO.getWeight());
                cmsDataDOList.set(index + 1, cmsDataDO);
                updateWeight(nextCmsDataDO, tmpWeight);
                index++;
            }
        }
    }


    /**
     * 重排
     *
     * @param cmsDataDO
     */
    private boolean updateWeight(CmsDataDO cmsDataDO, int newWeight) {
        cmsDataDO.setWeight(newWeight);
        return cmsDataManagerImpl.update(cmsDataDO);
    }
}